﻿using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;

namespace GDFlacTool.Common
{
    public class TagFromFileHelper
    {
        private readonly string _mask = string.Empty;
        private List<TagHelper> _tagHelpers = new List<TagHelper>();
        private int _tagCount;
        private int _nonTagCount;
        private readonly bool _replaceUnderscores;
        private readonly bool _useCase;
        private readonly CaseType _caseType;

        public TagFromFileHelper(string mask, bool replaceUnderscores, bool useCase, CaseType caseType)
        {
            _mask = mask;

            _replaceUnderscores = replaceUnderscores;

            _useCase = useCase;

            _caseType = caseType;

            _tagHelpers = TagsFromFileParser(_mask);
        }

        public List<TagHelper> GetTagHelper
        {
            get { return _tagHelpers; }
        }

        public int TagCount
        {
            get { return _tagCount; }
        }

        public int NonTagCount
        {
            get { return _nonTagCount; }
        }

        public List<TagHelper> Refresh(string mask)
        {
            _tagHelpers.Clear();

            _nonTagCount = 0;

            _tagCount = 0;

            _tagHelpers = TagsFromFileParser(mask);

            return _tagHelpers;
        }

        public List<TagFileObject> GetTagFromFilename(IList<Track> tracks, List<TagHelper> tagHelpers)
        {
            var ret = new List<TagFileObject>();

            foreach (Track track in tracks)
            {
                TagFileObject obj = CreateTags(Path.GetFileNameWithoutExtension(track.FullPath), tagHelpers);

                obj.FileName = track.FileName;

                ret.Add(obj);
            }

            return ret;
        }

        private TagFileObject CreateTags(string fileName, List<TagHelper> tagHelpers)
        {
            int pos = 0;

            string name;

            if (_replaceUnderscores)
            {
                name = fileName.Replace("_", " ");
            }
            else
            {
                name = fileName;
            }

            //string name = fileName;

            var obj = new TagFileObject();

            if(!tagHelpers[0].Variable.StartsWith("%"))
            {
                if(name.StartsWith(tagHelpers[0].Variable))
                {
                    name = name.Remove(0, tagHelpers[0].Variable.Length);
                    
                    pos = 1;
                }
            }

            for (int i = pos; i < tagHelpers.Count; i++)
            {
                string separator = string.Empty;

                string tagType = tagHelpers[i].TagType;

                if (i + 1 < tagHelpers.Count)
                {
                    if(!tagHelpers[i + 1].IsTag)
                    {
                        separator = tagHelpers[i + 1].Variable;

                        i++;
                    }
                }

                string[] value = Regex.Split(name, separator, RegexOptions.None);

                string tag;

                if(i == tagHelpers.Count - 1 && string.IsNullOrEmpty(separator))
                {
                    if(tagType == TagType.Remover)
                    {
                        tag = string.Empty;
                    }
                    else
                    {
                        tag = name;
                    }
                }
                else
                {
                    tag = value[0];

                    int lengt = tag.Length + separator.Length;

                    if(lengt <= name.Length)
                    {
                        name = name.Remove(0, lengt);
                    }
                    else
                    {
                        name = string.Empty;
                    }
                }

                //if(_replaceUnderscores)
                //{
                //    tag = tag.Replace("_", " ");
                //}

                if(_useCase)
                {
                    tag = CheckCase(tag, _caseType);
                }

                switch(tagType)
                {
                    case "ARTIST":
                        obj.Artist = tag;
                        break;
                    case "ALBUM":
                        obj.Album = tag;
                        break;
                    case "TITLE":
                        obj.Title = tag;
                        break;
                    case "DATE":
                        obj.Year = tag;
                        break;
                    case "TRACKNUMBER":
                        obj.Track = tag;
                        break;
                    case "DISCNUMBER":
                        obj.Disc = tag;
                        break;
                    case "GENRE":
                        obj.Genre = tag;
                        break;
                    case "COMMENT":
                        obj.Comment = tag;
                        break;
                    case "ALBUMARTIST":
                        obj.AlbumArtist = tag;
                        break;
                    case "CATALOG NUMBER":
                        obj.Catalog = tag;
                        break;
                }
            }

            return obj;
        }

        private string CheckCase(string text, CaseType type)
        {
            TextInfo myTI = new CultureInfo("en-US", false).TextInfo;

            string value = text;

            if (type != CaseType.None)
            {
                if (type == CaseType.Lower)
                {
                    value = myTI.ToLower(value);
                }

                if (type == CaseType.Upper)
                {
                    value = myTI.ToUpper(value);
                }

                if (type == CaseType.FirstLetter)
                {
                    value = myTI.ToTitleCase(value.ToLower());
                }

                if (type == CaseType.FirstWord)
                {
                    value = value.ToLower().ToUpperFirstLetter();
                }
            }

            return value;
        }

        private List<TagHelper> TagsFromFileParser(string mask)
        {
            string nonVarChar = string.Empty;
            bool isVarChar = false;
            var list = new List<TagHelper>();

            if(mask.Length == 0)
                return null;

            foreach (char chr in mask)
            {
                if(chr == '%')
                {
                    isVarChar = true;
                }
                else
                {
                    if(isVarChar)
                    {
                        if(!string.IsNullOrEmpty(nonVarChar))
                        {
                            list.Add(GetTagType(nonVarChar));
                            nonVarChar = string.Empty;

                            _nonTagCount = NonTagCount + 1;
                        }

                        list.Add( GetTagType("%" + chr));

                        _tagCount = TagCount + 1;

                        isVarChar = false;
                    }
                    else
                    {
                        nonVarChar += chr;
                    }
                }
            }

            if(!string.IsNullOrEmpty(nonVarChar))
            {
                list.Add(GetTagType(nonVarChar));
            }

            return list;
        }

        private TagHelper GetTagType(string variable)
        {
            switch (variable)
            {
                case "%1":
                    return new TagHelper("%1", TagType.Artist, "Artist", "Artist", true, 200);
                case "%2":
                    return new TagHelper("%2", TagType.Title, "Title", "Title", true, 200);
                case "%3":
                    return new TagHelper("%3", TagType.Album, "Album", "Album", true, 200);
                case "%4":
                    return new TagHelper("%4", TagType.Year, "Year", "Year", true, 40);
                case "%5":
                    return new TagHelper("%5", TagType.Genre, "Genre", "Genre", true, 80);
                case "%6":
                    return new TagHelper("%6", TagType.Tracknumber, "Track", "Track", true, 40);
                case "%7":
                    return new TagHelper("%7", TagType.Discnumber, "Disc", "Disc", true, 40);
                case "%C":
                    return new TagHelper("%C", TagType.Comment, "Comment", "Comment", true, 200);
                case "%A":
                    return new TagHelper("%A", TagType.Albumartist, "Album Artist", "AlbumArtist", true, 200);
                case "%G":
                    return new TagHelper("%G", TagType.CatalogNumber, "Catalog", "Catalog", true, 50);
                case "%d":
                    return new TagHelper("%d", TagType.Remover, "", "", true, 0);
                default:
                    return new TagHelper(variable, string.Empty, string.Empty, string.Empty, false, 0);
            }
        }
    }

    public class TagHelper
    {
        public TagHelper(string variable, string tagType, string name, string aspectName, bool isTag, int columnWidth)
        {
            Variable = variable;
            TagType = tagType;
            Name = name;
            IsTag = isTag;
            ColumnWidth = columnWidth;
            AspectName = aspectName;
        }

        public string AspectName { get; set; }

        public bool IsTag { get; set; }

        public string Variable { get; set; }

        public string TagType { get; set; }

        public string Name { get; set; }

        public int ColumnWidth { get; set; }
    }

    public class TagFileObject
    {
        public string FileName { get; set; }

        public string Artist { get; set; }

        public string Title { get; set; }

        public string Album { get; set; }

        public string Year { get; set; }

        public string Genre { get; set; }

        public string Track { get; set; }

        public string Disc { get; set; }

        public string Comment { get; set; }

        public string AlbumArtist { get; set; }

        public string Catalog { get; set; }
    }
}
